﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;

namespace Bittorrent.Bencode.Collections {
    internal class List : Object, IList<Object> {
        private readonly List<Object> _list = new List<Object>();

        public int IndexOf(Object item) {
            Contract.Requires(item != null);

            return _list.IndexOf(item);
        }

        public void Insert(int index, Object item) {
            Contract.Requires(index > 0);
            Contract.Requires(index < _list.Count);
            Contract.Requires(item != null);

            _list.Insert(index, item);
        }

        public void RemoveAt(int index) {
            Contract.Requires(index > 0);
            Contract.Requires(index < _list.Count);

            _list.RemoveAt(index);
        }

        public Object this[int index] {
            get {
                Contract.Requires(index > 0);
                Contract.Requires(index < _list.Count);

                return _list[index]; 
            }
            set {
                Contract.Requires(index > 0);
                Contract.Requires(index < _list.Count);
                Contract.Requires(value != null);

                _list[index] = value; 
            }
        }

        public int Count {
            get { return _list.Count; }
        }

        public bool IsReadOnly {
            get { return false; }
        }

        public void Add(Object item) {
            Contract.Requires(item != null);

            _list.Add(item);
        }

        public void Clear() {
            _list.Clear();
        }

        public bool Contains(Object item) {
            Contract.Requires(item != null);

            return _list.Contains(item);
        }

        public void CopyTo(Object[] array, int arrayIndex) {
            Contract.Requires(array != null);
            Contract.Requires(arrayIndex > 0);
            Contract.Requires(arrayIndex < array.Length);

            _list.CopyTo(array, arrayIndex);
        }

        public bool Remove(Object item) {
            Contract.Requires(item != null);

            return _list.Remove(item);
        }

        public IEnumerator<Object> GetEnumerator() {
            return _list.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }

        internal override int ByteSize {
            get {
                int size = Encoding.UTF8.GetByteCount("l");

                foreach (var item in _list) {
                    size += item.ByteSize;
                }

                size += Encoding.UTF8.GetByteCount("e");

                return size;
            }
        }

        internal override int Encode(byte[] data, int offset) {
            Contract.Requires(data != null);
            Contract.Requires(offset > 0);
            Contract.Requires(offset < data.Length);

            int written = Encoding.UTF8.GetBytes("l", 0, 1, data, offset);

            foreach (var item in _list) {
                written += item.Encode(data, offset + written);
            }

            written += Encoding.UTF8.GetBytes("e", 0, 1, data, offset + written);

            return written;
        }
    }
}
